package com.atguigu.daijia.dispatch.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.atguigu.daijia.common.constant.RedisConstant;
import com.atguigu.daijia.dispatch.mapper.OrderJobMapper;
import com.atguigu.daijia.dispatch.service.NewOrderService;
import com.atguigu.daijia.dispatch.xxl.client.XxlJobClient;
import com.atguigu.daijia.map.client.LocationFeignClient;
import com.atguigu.daijia.model.entity.dispatch.OrderJob;
import com.atguigu.daijia.model.enums.OrderStatus;
import com.atguigu.daijia.model.form.map.SearchNearByDriverForm;
import com.atguigu.daijia.model.vo.dispatch.NewOrderTaskVo;
import com.atguigu.daijia.model.vo.map.NearByDriverVo;
import com.atguigu.daijia.model.vo.order.NewOrderDataVo;
import com.atguigu.daijia.order.client.OrderInfoFeignClient;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author zqtao
 */
@Slf4j
@Service
@SuppressWarnings({"unchecked", "rawtypes"})
public class NewOrderServiceImpl implements NewOrderService {

    @Autowired
    private OrderJobMapper orderJobMapper;

    @Autowired
    private XxlJobClient xxlJobClient;

    @Override
    public Long addAndStartTask(NewOrderTaskVo newOrderTaskVo) {
        //需要先根据订单id，查询订单是否已经存在任务了
        LambdaQueryWrapper<OrderJob> orderJobLambdaQueryWrapper = new LambdaQueryWrapper<>();
        LambdaQueryWrapper<OrderJob> eq = orderJobLambdaQueryWrapper.eq(OrderJob::getOrderId, newOrderTaskVo.getOrderId());
        OrderJob orderJob = orderJobMapper.selectOne(eq);
        if(orderJob == null){
            //如果不存在，则新增订单任务即可
            //开启任务
            Long jobId = xxlJobClient.addAndStart("newOrderTaskHandler", "", "0 0/1 * * * ?", "新的订单任务：订单的id为：" + newOrderTaskVo.getOrderId());
            orderJob = new OrderJob();
            orderJob.setOrderId(newOrderTaskVo.getOrderId());
            orderJob.setJobId(jobId);
            orderJob.setParameter(JSONObject.toJSONString(newOrderTaskVo));
            orderJob.setCreateTime(new Date());
            orderJob.setUpdateTime(new Date());
            orderJobMapper.insert(orderJob);
        }
        //如果存在
        return orderJob.getJobId();
    }

    @Autowired
    private OrderInfoFeignClient orderInfoFeignClient;

    @Autowired
    private LocationFeignClient locationFeignClient;

    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public Boolean executeTask(Long jobId) {
        //需要先根据订单id，查询当前订单任务
        OrderJob orderJob = orderJobMapper.selectOne(new LambdaQueryWrapper<OrderJob>().eq(OrderJob::getJobId, jobId));

        if(orderJob == null){
            return true;
        }

        NewOrderTaskVo newOrderTaskVo = JSONObject.parseObject(orderJob.getParameter(), NewOrderTaskVo.class);

        //查询订单状态事是否是接单状态
        Integer status = orderInfoFeignClient.getOrderStatus(newOrderTaskVo.getOrderId()).getData();

        //判断订单返回的状态是接单还是不接单
        if(status != OrderStatus.WAITING_ACCEPT.getStatus().intValue()){
            //停止任务
            xxlJobClient.stopJob(jobId);
            System.out.println("订单状态不是等待接单状态，停止任务" + JSON.toJSONString(newOrderTaskVo));
            return true;
        }

        //搜索附近满足条件的司机
        SearchNearByDriverForm searchNearByDriverForm = new SearchNearByDriverForm();
        searchNearByDriverForm.setLongitude(newOrderTaskVo.getStartPointLongitude());
        searchNearByDriverForm.setLatitude(newOrderTaskVo.getStartPointLatitude());
        searchNearByDriverForm.setMileageDistance(newOrderTaskVo.getExpectDistance());

        //远程调用搜索附近司机的办法
        List<NearByDriverVo> nearByDriverVoList = locationFeignClient.searchNearByDriver(searchNearByDriverForm).getData();

        //给所有司机进行派单
        nearByDriverVoList.forEach(driver -> {
            //先获取每个司机的di，防止在派单的时候出现重复.
            String key = RedisConstant.DRIVER_ORDER_REPEAT_LIST + driver.getDriverId();

            //从redis中获取上一步的key，在redis中是否存在，如果不存在则开始接单，如果已经存在则不给司机派单
            Boolean member = redisTemplate.opsForSet().isMember(key, driver.getDriverId());

            if(Boolean.FALSE.equals(member)){
                //需要保存订单放到临时队列中
                redisTemplate.opsForSet().add(key,driver.getDriverId());
                //设置过期时间为15分钟 如果15分钟过期了，则订单取消
                redisTemplate.expire(key, RedisConstant.DRIVER_ORDER_REPEAT_LIST_EXPIRES_TIME, TimeUnit.MINUTES);
                //保存订单相关数据
                NewOrderDataVo newOrderDataVo = new NewOrderDataVo();
                newOrderDataVo.setOrderId(newOrderTaskVo.getOrderId());
                newOrderDataVo.setStartLocation(newOrderTaskVo.getStartLocation());
                newOrderDataVo.setEndLocation(newOrderTaskVo.getEndLocation());
                newOrderDataVo.setExpectAmount(newOrderTaskVo.getExpectAmount());
                newOrderDataVo.setExpectDistance(newOrderTaskVo.getExpectDistance());
                newOrderDataVo.setExpectTime(newOrderTaskVo.getExpectTime());
                newOrderDataVo.setFavourFee(newOrderTaskVo.getFavourFee());
                newOrderDataVo.setDistance(driver.getDistance());
                //将消息保存到消息队列中，司机上线开始接单后定时器就会推送到手机端
                String orderKey = RedisConstant.DRIVER_ORDER_TEMP_LIST + driver.getDriverId();
                redisTemplate.opsForList().leftPush(orderKey, JSONObject.toJSONString(newOrderDataVo));
                //队列里面的消息设置时间为一分钟
                redisTemplate.expire(orderKey, RedisConstant.DRIVER_ORDER_TEMP_LIST_EXPIRES_TIME, TimeUnit.MINUTES);
                System.out.println("信息订单已经存入redis的临时队列，订单数据为：" + newOrderDataVo);
            }
        });

        return true;
    }

    @Override
    public List<NewOrderDataVo> findNewOrderQueueData(Long driverId) {
        List<NewOrderDataVo> list = new ArrayList<>();
        //需要从redis的对列中获取key，获取key对应的value
        String key = RedisConstant.DRIVER_ORDER_TEMP_LIST + driverId;
        // 使用 opsForList() 而不是 opsForValue()
        Long size = redisTemplate.opsForList().size(key);
        if(size>0){
            for (int i = 0; i < size; i++) {
                String content = (String) redisTemplate.opsForList().leftPop(key);
                NewOrderDataVo newOrderDataVo = JSON.parseObject(content, NewOrderDataVo.class);
                list.add(newOrderDataVo);
            }
        }
        return list;
    }

    @Override
    public Boolean clearNewOrderQueueData(Long driverId) {
        //构建redis中的key
        String key = RedisConstant.DRIVER_ORDER_TEMP_LIST + driverId;
        redisTemplate.delete(key);
        return true;
    }
}
